<template>
  <el-table :data="tableData" :row-style="showRow" v-bind="$attrs" v-on="$listeners">
    <slot name="selection" />
    <slot name="pre-column" />
    <el-table-column v-for="item in columns" :label="item.label" :key="item.key" :width="item.width"
      :min-width="item.minWidth" :align="item.align||'center'" :header-align="item.headerAlign">
      <template slot="header">
        <slot>
          <template v-if="item.radio">
            <a @click="clearRadio" class="clear" v-if="radioSwitch">{{$t('BTN_NAME.CLEAR_AWAY')}}</a>
          </template>
          {{ item.label}}
        </slot>
      </template>
      <template slot-scope="scope">
        <slot :scope="scope" :name="item.key">
          <template v-if="item.expand">
            <span :style="{'padding-left':+scope.row._level*indent + 'px'} " />
            <span v-show="showSperadIcon(scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
              <i v-if="scope.row._isLoading" class="el-icon-loading"/>
              <i v-else-if="!scope.row._expand" class="el-icon-plus" @click="loadData(scope.row, scope.$index)"/>
              <i v-else class="el-icon-minus"/>
            </span>
          </template>
          <template v-if="item.checkbox">
            <el-checkbox v-if="scope.row[defaultChildren]&&scope.row[defaultChildren].length>0"
              :style="{'padding-left':+scope.row._level*indent + 'px'} " :indeterminate="scope.row._select && !checkStrictly"
              v-model="scope.row._select" @change="handleCheckAllChange(scope.row)" />
            <el-checkbox v-else :style="{'padding-left': checkStrictly ? 0 : scope.row._level*indent + 'px'} " v-model="scope.row._select"
              @change="handleCheckAllChange(scope.row)" />
          </template>
          <template v-if="item.radio">
            <el-radio :label="scope.$index" v-model="radio" @change="radioChange(scope.$index,scope.row)"
              class="table-radio">&nbsp;
            </el-radio>
          </template>
          {{ scope.row[item.key]}}
        </slot>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
  import treeToArray, {
    addAttrs
  } from './eval.js'

  export default {
    name: 'rfTreeTable',
    props: {
      data: {
        type: Array,
        required: true,
        default: () => []
      },
      columns: {
        type: Array,
        default: () => []
      },
      defaultExpandAll: {
        type: Boolean,
        default: false
      },
      defaultChildren: {
        type: String,
        default: 'children'
      },
      indent: {
        type: Number,
        default: 32
      },
      expandTier: {
        type: Number,
        default: 0
      },
      radioSwitch: {
        type: Boolean,
        default: true
      },
      // 是否进行懒加载
      lazy: {
        type: Boolean,
        default: false
      },
      // 在显示复选框的情况下，是否严格的遵循父子不互相关联的做法
      checkStrictly: {
        type: Boolean,
        default: false
      }
    },
    data () {
      return {
        guard: 1,
        radio: -1,
        tableData: []
      }
    },
    computed: {
      // 传入的children字段
      children () {
        return this.defaultChildren
      }
    },
    // 内部只操作tableData，不操作data
    watch: {
      data: {
        handler (newVal) {
          this.radio = -1
          this.tableData = newVal.slice(0)
          const data = this.tableData
          if (data.length === 0) {
            return []
          }
          // _expand是私有属性，用于组件的内部修改，expand是外部传入对分级按钮的控制
          addAttrs(data, {
            expand: this.defaultExpandAll,
            children: this.defaultChildren,
            expandTier: this.expandTier
          })
          this.tableData = treeToArray(data, this.defaultChildren)
        },
        deep: true
      }
    },
    methods: {
      // 点击头部清除按钮清除全部所选项
      clearRadio () {
        this.radio = -1
        this.$emit('selectData', {}, this.radio)
      },
      // 点击单行按钮触发事件
      radioChange (idx, sels) {
        this.radio = idx
        this.$emit('selectData', sels, this.radio)
      },
      // 是否展示当前行判断
      showRow: function ({
        row
      }) {
        const parent = row._parent
        const show = parent ? parent._expand && parent._show : true
        row._show = show
        return show
        ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
        : 'display:none;'
      },
      // 根据children的长度判断是否展示展开的icon
      showSperadIcon (record) {
        return (record[this.children] && record[this.children].length > 0) || (this.lazy && !record._isLeaf)
      },
      // 点击符号展开或收起
      toggleExpanded (trIndex) {
        const record = this.tableData[trIndex]
        const expand = !record._expand
        if (record._isLoading) return
        record._expand = expand
        if (this.lazy && !record._isLoad) {
          this.$set(record, '_isLoading', true)
        }
      },
      // 点击复选框,暴露选择事件
      handleCheckAllChange (row) {
        this.selcetRecursion(row, row._select, this.defaultChildren)
        this.isIndeterminate = row._select
        let selectData = this.tableData.filter(item => {
          if (item._select) {
            return item
          }
        })
        this.$emit('selectChange', selectData)
      },
      // 复选框联动处理
      selcetRecursion (row, select, children = 'children') {
        if (select) {
          this.$set(row, '_show', true)
          if (!this.checkStrictly) {
            this.$set(row, '_expand', true)
          }
        }
        if (this.checkStrictly) return
        const subItem = row[children]
        if (subItem && subItem.length > 0) {
          subItem.map(child => {
            child._select = select
            this.selcetRecursion(child, select, children)
          })
        }
      },
      // 懒加载触发事件
      loadData (row, index) {
        if (row._isLoad) return
        this.$emit('loadData', row, (node) => {
          this.tableData[index].children = node
          this.tableData[index]._isLoading = false
          addAttrs(this.tableData)
          if (row[this.children] && row[this.children].length > 0) {
            this.$set(row, '_isLeaf', false)
            row[this.children].forEach((item, index, arr) => {
              if (item.isLeaf) {
                this.$set(arr[index], '_isLeaf', true)
              }
            })
          } else {
            this.$set(row, '_isLeaf', true)
          }
          this.$set(row, '_isLoad', true)
          this.tableData = treeToArray(this.tableData, this.defaultChildren)
        })
      }
    },
    mounted () {

    }
  }
</script>

<style>
  @keyframes treeTableShow {
    from {
      opacity: 0;
    }

    to {
      opacity: 1;
    }
  }

  @-webkit-keyframes treeTableShow {
    from {
      opacity: 0;
    }

    to {
      opacity: 1;
    }
  }

  .tree-ctrl {
    position: relative;
    cursor: pointer;
    color: #2196f3;
  }

  .table-radio {
    width: 14px;
  }

  .clear {
    cursor: pointer;
    color: #2196f3;
  }
</style>
